package cc.rengu.oltp.service.base;

import cc.rengu.oltp.service.common.constant.AppConfigConstant;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.dao.*;
import cc.rengu.oltp.service.common.dao.impl.*;
import cc.rengu.oltp.service.common.entity.*;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.utility.util.RedisUtil;
import cc.rengu.oltp.utility.util.SQLMapperUtil;
import cc.rengu.oltp.utility.util.StringUtil;
import cc.rengu.oltp.utility.util.XmlConfigUtil;
import cc.rengu.utility.cache.UnifiedCache;
import com.alibaba.fastjson.JSON;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 共享缓存基础服务
 * Created by 王成 on 2017/11/22.
 */
public abstract class CacheBaseService extends RadpService {
    Set<String> dbPoolCashNode;

    @Override
    protected int bizInit(String s) {
        try {
            /* Step1：加载数据库SQL映射文件 */
            SQLMapperUtil.loadSQLMapperInfo();
            String sqlStr = (String) UnifiedCache.get(AppParamConstant.SQL_MAPPER_CACHE, "loadSrcTxnAuthCfgInfo");
            if (StringUtil.isEmptyOrNull(sqlStr)) {
                String oltpPath = URLDecoder.decode(getClass().getProtectionDomain().getCodeSource().getLocation().getPath(), "UTF-8");
                SQLMapperUtil.loadSqlMapperCache(new File(oltpPath).getAbsolutePath());
            }
            /* Step2：加载应用配置信息 */
            String applicationConfigName = System.getenv(AppParamConstant.IGAS_CONFIG);
            if (StringUtil.isEmptyOrNull(applicationConfigName)) {
                applicationConfigName = new File("").getCanonicalPath() + AppParamConstant.APPLICATION_CONFIG_FILE_NAME;
            }
            dbPoolCashNode = XmlConfigUtil.getDbCorporationInfo(applicationConfigName);
            XmlConfigUtil.loadXmlConfig(applicationConfigName);
            /* Step2.1：设置默认法人行及运行环境参数 */
            String defaultInstId = XmlConfigUtil.getXmlConfigCacheKeyValue(AppConfigConstant.APPLICATION_CONF_NODE, AppConfigConstant.DEFAULT_INST_ID);
            if (!StringUtil.isEmptyOrNull(defaultInstId)) {
                AppParamConstant.setDefaultInstId(defaultInstId.trim());
            }
            String applicationName = XmlConfigUtil.getXmlConfigNodeAttrValue(AppConfigConstant.APPLICATION_CONF_NODE, AppConfigConstant.APPLICATION_NAME);
            String applicationEnv = XmlConfigUtil.getXmlConfigNodeAttrValue(AppConfigConstant.APPLICATION_CONF_NODE, AppConfigConstant.APPLICATION_ENV);
            if (!StringUtil.isEmptyOrNull(applicationEnv)) {
                AppParamConstant.setApplicationEnv(applicationEnv.trim());
            }
            rglog.info("当用应用默认法人行:{},应用名称:{},应用环境:{}",defaultInstId,applicationName,applicationEnv);
            /* Step3：校验Redis是否已加载相关数据，或者是否强制加载 */
            String redisDataLoadFlag = RedisUtil.onceGet(AppParamConstant.REDIS_DATA_LOAD_FLAG);
            if (null != redisDataLoadFlag && !redisDataLoadFlag.isEmpty()) {
                String redisForceRefreshFlag = XmlConfigUtil.getXmlConfigNodeAttrValue(AppConfigConstant.REDIS_CONF_NODE, AppConfigConstant.REDIS_FORCE_REFRESH_FLAG);
                if (!Boolean.parseBoolean(redisForceRefreshFlag)) {
                    rglog.info("Redis已加载相关数据，不再重新加载!");
                    return 0;
                }
            }
            /* Step3.1：设置Redis加载参数标志为已加载，参数有效期为24小时，即每24小时最多加载一次 */
            RedisUtil.onceSet(AppParamConstant.REDIS_DATA_LOAD_FLAG, "true", 86400);
            /* Step4：加载渠道交易配置信息 */
            boolean txnInfoNullFlag = false;
            SrcTxnAuthCfgMapper srcTxnAuthCfgMapper = new SrcTxnAuthCfgMapperImpl();
            for (String dbCaseNodeName : dbPoolCashNode) {
                List<SrcTxnAuthCfg> srcTxnAuthCfgList = srcTxnAuthCfgMapper.loadSrcTxnAuthCfgInfo(dbCaseNodeName);
                if (null != srcTxnAuthCfgList && !srcTxnAuthCfgList.isEmpty()) {
                    txnInfoNullFlag = true;
                    RedisUtil.onceDel(AppParamConstant.TXN_INFO_CACHE);
                    for (SrcTxnAuthCfg srcTxnAuthCfg : srcTxnAuthCfgList) {
                        srcTxnAuthCfg.setTransChannelId(StringUtil.isEmptyOrNull(srcTxnAuthCfg.getTransChannelId()) ? "*" : srcTxnAuthCfg.getTransChannelId());
                        String txnKey = srcTxnAuthCfg.getInstId().trim() + srcTxnAuthCfg.getMsgSrcId().trim() + srcTxnAuthCfg.getTransChannelId().trim() + srcTxnAuthCfg.getTxnNum().trim() + srcTxnAuthCfg.getBizType().trim();
                        TxnInfo txnInfo = new TxnInfo();
                        txnInfo.setTxnKey(txnKey);
                        txnInfo.setSrcTxnAuthCfg(srcTxnAuthCfg);
                        /* Step4.1：获取交易异常配置信息 */
                        SrcTxnExcpCfgMapper srcTxnExcpCfgMapper = new SrcTxnExcpCfgMapperImpl();
                        SrcTxnExcpCfg srcTxnExcpCfg = srcTxnExcpCfgMapper.loadSrcTxnExcpCfgByPrimaryKey(dbCaseNodeName, srcTxnAuthCfg.getInstId(), srcTxnAuthCfg.getMsgSrcId(), srcTxnAuthCfg.getTxnNum(), srcTxnAuthCfg.getBizType());
                        if (null != srcTxnExcpCfg) {
                            txnInfo.setSrcTxnExcpCfg(srcTxnExcpCfg);
                        }
                        /* Step4.2：获取交易码通道服务调用配置信息 */
                        ChannelCallCfgMapper channelCallCfgMapper = new ChannelCallCfgMapperImpl();
                        List<ChannelCallCfg> channelCallCfgList = channelCallCfgMapper.loadChannelCallCfg(dbCaseNodeName, srcTxnAuthCfg.getInstId(), srcTxnAuthCfg.getMsgSrcId(), srcTxnAuthCfg.getTransChannelId(), srcTxnAuthCfg.getTxnNum(), srcTxnAuthCfg.getBizType());
                        if (null == channelCallCfgList || channelCallCfgList.isEmpty()) {
                            channelCallCfgList = channelCallCfgMapper.loadChannelCallCfg(dbCaseNodeName, srcTxnAuthCfg.getInstId(), srcTxnAuthCfg.getMsgSrcId(), "*", srcTxnAuthCfg.getTxnNum(), srcTxnAuthCfg.getBizType());
                        }
                        if (null != channelCallCfgList && !channelCallCfgList.isEmpty()) {
                            channelCallCfgList = channelCallCfgList.stream().sorted(Comparator.comparing(ChannelCallCfg::getCallIndex)).collect(Collectors.toList());
                            channelCallCfgList.forEach(item -> {
                                if (item.getSyncQueryRepeatTime() > 0){
                                    item.setSyncQueryRepeatTime(item.getSyncQueryRepeatTime() * 1000);
                                }
                            });
                            txnInfo.setChannelCallCfgList(channelCallCfgList);
                        }
                        /* Step4.3：将交易信息加载到缓存中 */
                        rglog.info("渠道交易权限配置信息：KEY<{}>,VALUE<{}>", txnKey, JSON.toJSONString(txnInfo));
                        RedisUtil.hashSet(AppParamConstant.TXN_INFO_CACHE, txnKey, JSON.toJSONString(txnInfo));
                    }
                }
            }
            if (!txnInfoNullFlag) {
                rglog.warn("渠道交易配置信息为空.");
            }

            /* Step5：加载通道交易权限配置信息 */
            List<DstTxnAuthCfg> dstTxnAuthCfgList = new ArrayList<>();
            DstTxnAuthCfgMapper dstTxnAuthCfgMapper = new DstTxnAuthCfgMapperImpl();
            dstTxnAuthCfgMapper.loadAllDstTxnAuthCfg(dbPoolCashNode, dstTxnAuthCfgList);
            if (!dstTxnAuthCfgList.isEmpty()) {
                RedisUtil.onceDel(AppParamConstant.CHANNEL_TXN_CACHE);
                for (DstTxnAuthCfg dstTxnAuthCfg : (dstTxnAuthCfgList.stream().distinct().collect(Collectors.toList()))) {
                    String key = dstTxnAuthCfg.getInstId().trim() + dstTxnAuthCfg.getMsgDstId().trim() + dstTxnAuthCfg.getChannelTxn().trim();
                    rglog.info("通道交易权限配置信息：KEY<{}>,VALUE<{}>", key, JSON.toJSONString(dstTxnAuthCfg));
                    RedisUtil.hashSet(AppParamConstant.CHANNEL_TXN_CACHE, key, JSON.toJSONString(dstTxnAuthCfg));
                }
            } else {
                rglog.warn("数据库连接池对应的支付通道交易权限配置信息为空.");
            }

            /* Step6：加载全量映射码转换关系配置 */
            List<RspCodeMap> rspCodeMapList = new ArrayList<>();
            RspCodeMapMapper rspCodeMapMapper = new RspCodeMapMapperImpl();
            rspCodeMapMapper.loadAllRespCodeMapInfo(dbPoolCashNode, rspCodeMapList);
            if (!rspCodeMapList.isEmpty()) {
                RedisUtil.onceDel(AppParamConstant.RSP_CODE_MAP_CACHE);
                rspCodeMapList = rspCodeMapList.stream().sorted(Comparator.comparing(RspCodeMap::getSrcRspCode)).collect(Collectors.toList());
                Map<String, List<RspCodeMap>> rspCodeMaps = new HashMap<>();
                for (RspCodeMap rspCodeMap : rspCodeMapList) {
                    String rspCodeMapkey = rspCodeMap.getInstId().trim() + rspCodeMap.getSrcSysId().trim() + rspCodeMap.getSrcRspCode().trim();
                    if (!rspCodeMaps.isEmpty() && null != rspCodeMaps.get(rspCodeMapkey)) {
                        rspCodeMaps.get(rspCodeMapkey).add(rspCodeMap);
                    } else {
                        List<RspCodeMap> rspCodeMapTmpList = new ArrayList<>();
                        rspCodeMapTmpList.add(rspCodeMap);
                        rspCodeMaps.put(rspCodeMapkey, rspCodeMapTmpList);
                    }
                }
                for (String rspCodeMapKey : rspCodeMaps.keySet()) {
                    List<RspCodeMap> rspCodeMapsTmp = rspCodeMaps.get(rspCodeMapKey);
                    rglog.info("映射码转换关系配置KEY:<{}>,VALUE:<{}>", rspCodeMapKey, JSON.toJSONString(rspCodeMapsTmp));
                    RedisUtil.hashSet(AppParamConstant.RSP_CODE_MAP_CACHE, rspCodeMapKey, JSON.toJSONString(rspCodeMapsTmp));
                }
            } else {
                rglog.warn("数据库连接池对应的映射码转换关系配置信息为空.");
            }

            /* Step7：加载交易渠道信息 */
            List<SrcChannelInfo> srcChannelInfoList = new ArrayList<>();
            SrcChannelInfoMapper srcChannelInfoMapper = new SrcChannelInfoMapperImpl();
            srcChannelInfoMapper.loadAllSrcChannelInfo(dbPoolCashNode, srcChannelInfoList);
            if (!srcChannelInfoList.isEmpty()) {
                RedisUtil.onceDel(AppParamConstant.CHANNEL_ACQ_INFO_CACHE);
                for (SrcChannelInfo srcChannelInfo : (srcChannelInfoList.stream().distinct().collect(Collectors.toList()))) {
                    String srcChannelInfoKey = srcChannelInfo.getInstId().trim() + srcChannelInfo.getSrcChannelId().trim() + srcChannelInfo.getTransChannelId().trim();
                    rglog.info("交易渠道信息配置KEY:<{}>,VALUE:<{}>", srcChannelInfoKey, JSON.toJSONString(srcChannelInfo));
                    RedisUtil.hashSet(AppParamConstant.CHANNEL_ACQ_INFO_CACHE, srcChannelInfoKey, JSON.toJSONString(srcChannelInfo));
                }
            } else {
                rglog.warn("交易渠道信息为空.");
            }

            /* Step8：加载支付通道信息 */
            List<DstChannelInfo> dstChannelInfoList = new ArrayList<>();
            DstChannelInfoMapper dstChannelInfoMapper = new DstChannelInfoMapperImpl();
            dstChannelInfoMapper.loadAllDstChannelInfo(dbPoolCashNode, dstChannelInfoList);
            if (!dstChannelInfoList.isEmpty()) {
                RedisUtil.onceDel(AppParamConstant.CHANNEL_ISS_INFO_CACHE);
                for (DstChannelInfo dstChannelInfo : (dstChannelInfoList.stream().distinct().collect(Collectors.toList()))) {
                    String dstChannelInfoKey = dstChannelInfo.getInstId().trim() + dstChannelInfo.getDstChannelId().trim();
                    rglog.info("支付通道信息配置KEY:<{}>,VALUE:<{}>", dstChannelInfoKey, JSON.toJSONString(dstChannelInfo));
                    RedisUtil.hashSet(AppParamConstant.CHANNEL_ISS_INFO_CACHE, dstChannelInfoKey, JSON.toJSONString(dstChannelInfo));
                }
                /* Step8.1 加载通道配置信息 */
                List<DstChannelCfg> dstChannelCfgList = new ArrayList<>();
                DstChannelCfgMapper dstChannelCfgMapper = new DstChannelCfgMapperImpl();
                dstChannelCfgMapper.loadAllDstChannelCfg(dbPoolCashNode, dstChannelCfgList);
                if (!dstChannelCfgList.isEmpty()) {
                    RedisUtil.onceDel(AppParamConstant.CHANNEL_INFO_CFG_CACHE);
                    for (DstChannelCfg dstChannelCfg : (dstChannelCfgList.stream().distinct().collect(Collectors.toList()))) {
                        String dstChannelCfgKey = dstChannelCfg.getInstId().trim() + dstChannelCfg.getDstChannelId().trim() + dstChannelCfg.getDstChannelType().trim();
                        rglog.info("支付通道配置信息KEY:<{}>,VALUE:<{}>", dstChannelCfgKey, JSON.toJSONString(dstChannelCfg));
                        RedisUtil.hashSet(AppParamConstant.CHANNEL_INFO_CFG_CACHE, dstChannelCfgKey, JSON.toJSONString(dstChannelCfg));
                    }
                }
            } else {
                rglog.warn("支付通道信息为空.");
            }

            /* Step9：加载客户化共享数据 */
            boolean loadFlag = customShareCacheLoad();
            if (!loadFlag) {
                rglog.warn("加载自定义共享缓存数据失败!");
                return -1;
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            rglog.error("共享缓存初始化失败<{}>", byteArrayOutputStream.toString());
            return -1;
        }
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {
        return 0;
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }

    /**
     * 加载自定义缓存信息
     *
     * @return true-成功,false-失败
     */
    protected abstract boolean customShareCacheLoad() throws Exception;
}
